#include "FontManager.h"
#include <fstream>
using std::fstream;

FontManager FontManager::m_Instance;

FontManager* FontManager::GetInstance(void)
{
	return &m_Instance;
}

FontManager::FontManager(void)
{

}

FontManager::~FontManager(void)
{
	Shutdown();
}

void FontManager::Initialize(void)
{
	m_TM = TextureManager::GetInstance();
	m_Fonts.RemoveAll();
}

unsigned int FontManager::LoadFont(const char* fileName, unsigned int style)
{
	Font* fontStream = new Font();

	fstream fIn(fileName, std::ios::in | std::ios::binary);

	if( fIn.is_open() && fIn.good() )
	{
		// Make sure to move back to the beginning
		fIn.seekg(fIn.beg);
		// Read in texture file and color key
		char texture[32] = { 0 };
		texture[17] = 64;
		char fullTexture[64] = { 0 };
		DWORD colorKey = 0;
		char strLength = 0;
		fIn.read((char*)&colorKey, sizeof(DWORD));
		fIn.read((char*)&strLength, 1);
		fIn.read((char*)&texture, strLength);
		sprintf_s(fullTexture, "../Resource/%s", texture);
		fontStream->m_FontTextureID = m_TM->LoadTeture(fullTexture, colorKey);

		// Read in some more stuff, such as the 'size' of the font, 
		// And row/column count
		fIn.read((char*)&fontStream->m_FontWidth, sizeof(int));
		fIn.read((char*)&fontStream->m_FontHeight, sizeof(int));
		fIn.read((char*)&fontStream->m_FontColumnCount, sizeof(int));
		fIn.read((char*)&fontStream->m_FontRowCount, sizeof(int));

		// Read in the starting letter info, and letter count
		Font::Letter letterStream;		
		char letterCount = 0;
		fIn.read((char*)&letterCount, sizeof(letterCount));

		for(char letter = 0; letter < letterCount; letter++)
		{
			fIn.read((char*)&letterStream.m_Letter, sizeof(letterStream.m_Letter));
			fIn.read((char*)&letterStream.m_OffsetX, sizeof(letterStream.m_OffsetX));
			fIn.read((char*)&letterStream.m_OffsetY, sizeof(letterStream.m_OffsetY));
			fIn.read((char*)&letterStream.m_Width, sizeof(letterStream.m_Width));
			fIn.read((char*)&letterStream.m_Height, sizeof(letterStream.m_Height));
			fIn.read((char*)&letterStream.m_Spacing, sizeof(letterStream.m_Spacing));

			if( letter == 0 )
			{
				fontStream->m_FontStartingLetter = letterStream.m_Letter;
			}

			fontStream->m_FontLetters.AddBack(letterStream);
		}

		m_Fonts.AddBack(fontStream);
	}
	else
	{
		fIn.close();
		fIn.clear();
	
		return UINT_MAX;
	}

	fIn.close();
	fIn.clear();

	return m_Fonts.Size();
}

void FontManager::HandleStyle(char* string, int style, int index, float& scaleX, float& scaleY)
{
	switch( style )
	{
	case STYLE_WOWMAIL:
		{
			if( index == 0 || (m_NewLine && string[index] != '\n' && string[index] != ' ') )
			{
				float x = scaleX, y = scaleY;
				scaleX = (x + x);
				scaleY = (y + y);
				m_NewLine = false;
			}
		}
		break;
	case STYLE_CAMELHUMP:
		{
			if( !(index%2) )
				string[index] = toupper(string[index]);
		}
		break;
	default:
	case STYLE_NORMAL:
		{
			break;
		}
		break;
	}
}

void FontManager::Draw(const char* string, unsigned int font, int style, int x, int y, float scaleX, float scaleY)
{
	Font* drawFont = m_Fonts[font];
	int len = strlen(string);
	
	// Make sure it isn't too long
	if( len > MAX_STRLEN )
		len = MAX_STRLEN;

	// Copy to modify
	strcpy_s(m_String, MAX_STRLEN, string);

	// Temporary values
	RECT rect;
	char letter = 0, prvLetter = 0;
	int rX = 0, rY = 0,
		printX = x, printY = y;
	float _scaleX = scaleX, _scaleY = scaleY;

	char flttr = drawFont->m_FontStartingLetter;
	// Loop through each character
	for(int str = 0; str < len; str++)
	{
		// Fix scale
		_scaleX = scaleX;
		_scaleY = scaleY;

		// Handle a new line
		if( m_String[str] == '\n' )
		{
			printY += drawFont->m_FontHeight;
			printX = x;
			m_NewLine = true;
			continue;
		}

		// Handle a tab
		if( m_String[str] == '\t' )
		{
			printX += drawFont->m_FontWidth*4;
			continue;
		}

		// If the character
		if( m_String[str] < drawFont->m_FontStartingLetter )
			letter = 0;
		else
			letter = m_String[str]-flttr;

		// Create a rectangle that it'll draw from
		rX = letter%drawFont->m_FontColumnCount;
		rY = (letter-rX)/drawFont->m_FontColumnCount;
		rX *= drawFont->m_FontWidth; 
		rY *= drawFont->m_FontHeight;
		
		rect.left = rX + drawFont->m_FontLetters[letter].m_OffsetX;
		rect.right = rect.left + drawFont->m_FontLetters[letter].m_Width;
		rect.top = rY + drawFont->m_FontLetters[letter].m_OffsetY;
		rect.bottom = rect.top + drawFont->m_FontLetters[letter].m_Height;

		// Handle the font
		HandleStyle((char*)m_String, style, str, _scaleX, _scaleY);

		// Take care of scale
		int shiftY = 0;
		if( _scaleY > scaleY )
		{
			shiftY = rect.bottom-rect.top;
			shiftY = (int)((float)shiftY * (_scaleY-scaleY));
		}
		else if( _scaleY < scaleY )
		{
			shiftY = -(rect.bottom-rect.top);
			shiftY = (int)((float)shiftY * (_scaleY+scaleY));
		}

		// Draw this thing
		m_TM->Draw(drawFont->m_FontTextureID, printX, printY-shiftY, _scaleX, _scaleY, &rect, 
			(float)(m_Fonts[font]->m_FontWidth/2), (float)(m_Fonts[font]->m_FontHeight/2));

		printX += (int)((_scaleX*(rect.right - rect.left)) + (_scaleX*drawFont->m_FontLetters[letter].m_Spacing));
	}
}

void FontManager::Shutdown(void)
{
	Font* deleteThis = NULL;

	for(unsigned int ff = 0; ff < m_Fonts.Size(); ff++)
	{
		deleteThis = m_Fonts[ff];
		m_Fonts[ff] = NULL;

		if( deleteThis )
		{
			delete deleteThis;
		}
	}
}